//
//  NEDRouter.m
//  MoreCoin
//
//  Created by 林宁宁 on 2019/9/19.
//  Copyright © 2019 MoreCoin. All rights reserved.
//

#import "NEDRouter.h"

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

#import "NEDRouter+Jump.h"
#import "NEDRouter+Map.h"
#import "BifrostHeader.h"
#import "NEDApp+Mediator.h"

UIViewController * NEDFilterVCLoop(UIViewController * vc){
    UIViewController *result = vc;
    while (result.presentedViewController) {
        result = result.presentedViewController;
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        result = [(UITabBarController *)result selectedViewController];
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        result = [(UINavigationController *)result topViewController];
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        return NEDFilterVCLoop(result);
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        return NEDFilterVCLoop(result);
    }
    return result;
}

UIViewController * NEDCurrentViewController(void){
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal){
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows){
            if (tmpWin.windowLevel == UIWindowLevelNormal){
                window = tmpWin;
                break;
            }
        }
    }
    UIViewController *result = NEDFilterVCLoop(window.rootViewController);
    if([result isKindOfClass:NSClassFromString(@"RTContainerController")]){
        SEL cnSel = NSSelectorFromString(@"contentViewController");
        if([result respondsToSelector:cnSel]){
            result = [result performSelector:cnSel];
        }
    }
    return result;
}

UINavigationController * _NEDCurrentNavigationViewControllerRecursive(UIViewController * vc){
    UIResponder *next = [vc.view nextResponder];
    do {
        if ([next isKindOfClass:[UINavigationController class]]) {
            return (UINavigationController *)next;
        }
        if ([next isKindOfClass:[UITabBarController class]]) {
            next = [(UITabBarController *)next selectedViewController];
        }else{
            next = [next nextResponder];
        }
    } while (next !=nil);

    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal){
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows){
            if (tmpWin.windowLevel == UIWindowLevelNormal){
                window = tmpWin;
                break;
            }
        }
    }
    UIViewController *result = window.rootViewController;
    if ([result isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)result;
    }
    
    while (result.presentedViewController) {
        result = result.presentedViewController;
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        result = [(UITabBarController *)result selectedViewController];
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)result;
    }
    return nil;
}

UINavigationController * NEDCurrentNavigationViewController(void){
    UIViewController * currentVC = NEDCurrentViewController();
    UINavigationController * currentNAVC = _NEDCurrentNavigationViewControllerRecursive(currentVC);
    if(currentNAVC){
        return currentNAVC;
    }
    if(currentVC.presentingViewController){
        currentNAVC = _NEDCurrentNavigationViewControllerRecursive(currentVC.presentingViewController);
        if(currentNAVC){
            return currentNAVC;
        }
    }
    return nil;
}


#pragma mark - NEDRouterPrivite 在 UIViewController+NEDRouter 中实现

@interface UIViewController (NEDRouterPrivite)

/// router的传参
@property (retain, nonatomic) NSDictionary * ned_routerParams;

/// 该控制器只能有一个， 如果已有则刷新该控制器数据 并 pop回到该控制器
- (UIViewController *(^)(void))ned_singletonAtNavigation;
- (UIViewController *(^)(void))ned_singletonAtWindow;
/// 判断控制器需要登录操作
/// vc中需在ned_routerNeedLoginFirst中声明 未声明则不做处理
- (UIViewController *(^)(void))ned_needLogin;

@end


#pragma mark - NEDRouter

@implementation NEDRouter

+ (instancetype)sharedManager {
    static NEDRouter *router = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        if (!router) {
            router = [[self alloc] init];
            router.navigationViewClass = UINavigationController.class;
            router.mapKeys = [NSMutableDictionary new];
            router.mapHandles = [NSMutableDictionary new];
            
            [Bifrost setExceptionHandler:^id _Nullable(NSException * _Nonnull exception) {
                NSLog(@"[Module] Exception:%@", exception);
                switch (exception.bf_exceptionCode) {
                    case BFExceptionUrlHandlerNotFound:
                        [router __errorHandle:NEDRouterErrorCodeBFUrlHandlerNotFound reason:exception.reason params:exception.userInfo];
                        break;
                    case BFExceptionModuleNotFoundException:
                        [router __errorHandle:NEDRouterErrorCodeBFModuleNotFoundException reason:exception.reason params:exception.userInfo];
                        break;
                    case BFExceptionAPINotFoundException:
                        [router __errorHandle:NEDRouterErrorCodeBFAPINotFoundException reason:exception.reason params:exception.userInfo];
                        break;
                    case BFExceptionFailedToRegisterModule:
                        [router __errorHandle:NEDRouterErrorCodeBFFailedToRegisterModule reason:exception.reason params:exception.userInfo];
                        break;
                    default:
                        break;
                }
                return nil;
            }];
        }
    });
    return router;
}

#pragma mark -

+ (UIViewController *)ned_queryControllerKey:(NSString *)vcKey params:(NSDictionary * _Nullable)params {
    if(params && ![params isKindOfClass:NSDictionary.class]){
        [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeParameterTypeError reason:@"参数类型错误" params:@{@"key":vcKey,@"param":params?:@{}}];
        return nil;
    }
    // 判断他的handle map中是否有自定义处理
    if([NEDRouter sharedManager].mapHandles[vcKey]){
        NEDRouterHandleBlock block = [NEDRouter sharedManager].mapHandles[vcKey];
        block(params);
        return nil;
    }
    
    if([NEDRouter sharedManager].parameterHandler){
        params = [NEDRouter sharedManager].parameterHandler(params);
    }
    if([NEDRouter sharedManager].continueHandler){
        BOOL toContiues = [NEDRouter sharedManager].continueHandler(params);
        if(!toContiues){
            return nil;
        }
    }
    if(IsNonNull(vcKey)){
        UIViewController * vc = [NEDRouter ned_controllerKey:vcKey];
        if(!vc){
            return nil;
        }
        if(params){
            id v = vc.ned_params(params);
            if(!v){
                [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeConfigOpertionBreakOff reason:@"配置 返回空" params:@{@"key":vcKey}];
                return nil;
            }
        }
        return vc;
    }
    else{
        [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeKeyMapFormatError reason:@"vcKey 为空" params:nil];
        return nil;
    }
}

/// MARK: - Push Present

+ (UIViewController *)ned_pushKey:(NSString *)vcKey{
    return [NEDRouter ned_pushKey:vcKey params:nil];
}
+ (UIViewController *)ned_pushKey:(NSString *)vcKey params:(NSDictionary * _Nullable)params{
    UIViewController * vc = [NEDRouter ned_queryControllerKey:vcKey params:params];
    if(!vc){
        return nil;
    }
    return [vc ned_push];
}


+ (UIViewController *)ned_presentKey:(NSString *)vcKey{
    return [NEDRouter ned_presentKey:vcKey params:nil];
}
+ (UIViewController *)ned_presentKey:(NSString *)vcKey params:(NSDictionary * _Nullable)params{
    UIViewController * vc = [NEDRouter ned_queryControllerKey:vcKey params:params];
    if(!vc){
        return nil;
    }
    if(vc.isViewLoaded){
        //不做跳转
        return vc.ned_reloadViewContent();
    }
    return [vc ned_present];
}


/// MARK: - Jump

/// 跳转前准备
+ (UIViewController * _Nullable)__ned_jumpPrepare:(UIViewController *)vc{
    if(!vc){
        return nil;
    }
    /// 判断是否需要登录  是否唯一
    if(!vc.ned_singletonAtNavigation()){
        return nil;
    }
    if(!vc.ned_singletonAtWindow()){
        return nil;
    }
    if(!vc.ned_needLogin()){
        return nil;
    }
    return vc;
}

+ (void)ned_pushViewController:(UIViewController *)vc{
    /// 判断是否需要登录  是否唯一
    if(![NEDRouter __ned_jumpPrepare:vc]){
        return;
    }
    UINavigationController * navc = NEDCurrentNavigationViewController();
    if(navc){
        [navc pushViewController:vc animated:YES];
    }else{
        [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeNavigationNotFound reason:@"没有找到导航控制器, 使用Present打开控制器" params:nil];
        
        [NEDRouter ned_presentViewController:vc prepare:NO];
    }
}

+ (void)ned_presentViewController:(UIViewController *)vc{
    [NEDRouter ned_presentViewController:vc prepare:YES];
}

+ (void)ned_presentViewController:(UIViewController *)vc prepare:(BOOL)prepare{
    if(prepare && ![NEDRouter __ned_jumpPrepare:vc]){
        return;
    }
    UINavigationController * navc = [[[NEDRouter sharedManager].navigationViewClass alloc] initWithRootViewController:vc];
    navc.modalPresentationStyle = UIModalPresentationFullScreen;
    
    __weak typeof(&*vc)weakVC = vc;
    void(^addNavigationCloseItem)(void) = ^(void) {
        UIView * customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
        UIButton * closeBtn;
        if(APP.mediator.delegateStyle &&
           [APP.mediator.delegateStyle respondsToSelector:@selector(style_viewcontrollerBackBarItemImageName)]){
            UIImage * backImage = [UIImage imageNamed:[APP.mediator.delegateStyle style_viewcontrollerBackBarItemImageName]];
            closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            [closeBtn setImage:backImage forState:UIControlStateNormal];
        }else if (@available(iOS 13.0, *)){
            closeBtn = [UIButton buttonWithType:UIButtonTypeClose];
        }else{
            closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            [closeBtn setTitle:@"关闭" forState:UIControlStateNormal];
            [closeBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        }
        [closeBtn addTarget:vc action:@selector(ned_dismiss) forControlEvents:(UIControlEventTouchUpInside)];
        closeBtn.frame = CGRectMake(0, 0, 44, 44);
        closeBtn.center = customView.center;
        [customView addSubview:closeBtn];
        
        weakVC.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];
    };
    addNavigationCloseItem();
    
    [NEDCurrentViewController() presentViewController:navc animated:YES completion:^{
    }];
}
 

#pragma mark - URL

NSMutableDictionary * NEDRouterParseComponentParams(NSString * urlString){
    NSMutableDictionary * queryParams = [NSMutableDictionary dictionary];
    if(IsNull(urlString)){
        return queryParams;
    }
    NSURLComponents *components = [NSURLComponents componentsWithString:[urlString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]];
    if (components.fragment != nil) {
        BOOL fragmentContainsQueryParams = NO;
        NSURLComponents *fragmentComponents = [NSURLComponents componentsWithString:components.percentEncodedFragment];
        if (fragmentComponents.query == nil && fragmentComponents.path != nil) {
            fragmentComponents.query = fragmentComponents.path;
        }
        if (fragmentComponents.queryItems.count > 0) {
            fragmentContainsQueryParams = fragmentComponents.queryItems.firstObject.value.length > 0;
        }
        if (fragmentContainsQueryParams) {
            components.queryItems = [(components.queryItems ?: @[]) arrayByAddingObjectsFromArray:fragmentComponents.queryItems];
        }
    }
    //获取queryItem
    NSArray <NSURLQueryItem *> *queryItems = [components queryItems] ?: @[];
    for (NSURLQueryItem *item in queryItems) {
        if (item.value == nil) {
            continue;
        }
        if (queryParams[item.name] == nil) {
            queryParams[item.name] = [item.value stringByRemovingPercentEncoding];
        } else if ([queryParams[item.name] isKindOfClass:[NSArray class]]) {
            NSArray *values = (NSArray *)(queryParams[item.name]);
            queryParams[item.name] = [values arrayByAddingObject:[item.value stringByRemovingPercentEncoding]];
        } else {
            id existingValue = queryParams[item.name];
            queryParams[item.name] = @[existingValue, [item.value stringByRemovingPercentEncoding]];
        }
    }
    return queryParams;
}

+ (UIViewController *)ned_openLink:(NSString *)URL{
    return [NEDRouter ned_openLink:URL appendParams:nil];
}
+ (UIViewController *)ned_openLink:(NSString *)URL appendParams:(NSDictionary * _Nullable)appendParams{
    if (IsNull(URL)) {
        [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeURLWrongful reason:@"传入的URL为空" params:nil];
        return nil;
    }
    NSURLComponents *components = [NSURLComponents componentsWithString:[URL stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]];
    NSString * scheme = components.scheme;
    
    //链接中的参数信息
    NSMutableDictionary * params = NEDRouterParseComponentParams(URL);
    if(appendParams){
        [params addEntriesFromDictionary:appendParams];
    }
    
    NSString * vcHost = nil;
    
    // 是自定义scheme类型的链接
    if(![scheme.lowercaseString hasPrefix:@"http"]){
        // 不是自己想要的
        if ([NEDRouter sharedManager].urlScheme &&
            ![scheme isEqualToString:[NEDRouter sharedManager].urlScheme]) {
            [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeURLSchemeMismatch reason:[NSString stringWithFormat:@"url中的scheme：%@ 跟自定义的：%@不匹配",scheme,[NEDRouter sharedManager].urlScheme] params:@{@"scheme":NullShow(scheme)}];
            return nil;
        }
        if (components.host.length > 0 &&
            ![components.host isEqualToString:@"localhost"] &&
            [components.host rangeOfString:@"."].location == NSNotFound) {
            NSString * host = components.percentEncodedHost;
            if(IsNonNull(host)){
                NSString * appIn = NullShow([NEDRouter sharedManager].urlComponentsHostAppIn);
                NSString * appOut = NullShow([NEDRouter sharedManager].urlComponentsHostAppOut);
                NSString * path = components.percentEncodedPath;
                // 外部打开链接
                if([host isEqualToString:appOut]){
                    NSArray * outKeys = @[@"url",@"link"];
                    for(NSString * key in outKeys){
                        if(params[key] &&
                           [params[key] isKindOfClass:[NSString class]]){
                            [NEDRouter jump_openURLOutside:params[key]];
                            break;
                        }
                    }
                    return nil;
                }
                else if([host isEqualToString:appIn] &&
                        IsNonNull(path)){
                    vcHost = [path componentsSeparatedByString:@"/"].lastObject;
                }
                else{
                    vcHost = host;
                }
            }
        }
    }
    // 如果路径为空 判断参数中是否有控制器的信息
    if(IsNull(vcHost)){
        vcHost = [[NEDRouter sharedManager] __queryPageNameAtURLPathParams:params];
    }
    if(IsNull(vcHost)){
        return [NEDRouter jump_openWebViewByURL:URL params:params];
    }else{
        return [NEDRouter ned_pushKey:vcHost params:params];
    }
}

/// 通过自定义的 pagekeypath 来查找控制器信息
- (NSString *)__queryPageNameAtURLPathParams:(NSDictionary *)params{
    if(![params isKindOfClass:[NSDictionary class]]){
        return nil;
    }
    if(!self.URLPageKeypaths){
        [[NEDRouter sharedManager] __errorHandle:NEDRouterErrorCodeConfigIncomplete reason:@"未设置 URLPageKeypaths 信息" params:nil];
        return nil;
    }
    for(NSString * key in self.URLPageKeypaths){
        id path = [params objectForKey:key];
        if(path && ![path isKindOfClass:[NSNull class]]){
            return path;
        }
    }
    return nil;
}

#pragma mark - error

- (void)__errorHandle:(NEDRouterErrorCode)code reason:(NSString *)reason params:(NSDictionary * _Nullable)params{
    if(self.errorHandler){
        self.errorHandler(code,reason,params);
    }
}


@end
